#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <unistd.h>
#include <fcntl.h>
#include <string.h>
#include <sys/stat.h>
#include <sys/file.h>
#include <syslog.h>
#include <errno.h>

#define BUFSIZE		64
#define FILENAME	"/tmp/out"
#define LOCKFILE	"/tmp/lock" // "/var/run/daemon.pid"访问权限有限制，会访问失败

#define LOCKMODE (S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH)

int my_daemon(void);

int already_running(void);

int main(void)
{
	char buf[BUFSIZE];
	int fd;
	time_t current;
	struct tm *tm;	

	openlog("mydaemon", LOG_PID, LOG_DAEMON);

	if (already_running()) {
		syslog(LOG_ERR, "Already running!\n");
		return 0;
	}

	if (-1 == my_daemon()) {
		syslog(LOG_ERR, "Error creating daemon: %s\n", strerror(errno));
		exit(1);
	}

	fd = open(FILENAME, O_CREAT | O_WRONLY | O_TRUNC);
	if (-1 == fd) {
		syslog(LOG_ERR, "Error opening file: %s\n", strerror(errno));
		exit(1);
	}

	while (1) {
		current = time(NULL);
		tm = localtime(&current);
		
		memset(buf, '\0', BUFSIZE);
		strftime(buf, BUFSIZE, "%Y/%m/%d %H:%M:%S", tm);

		//syslog(LOG_INFO, buf);
		
		lseek(fd, 0, SEEK_SET);
		write(fd, buf, BUFSIZE);

		sleep(1);
	}

	return 0;
}

int my_daemon(void)
{
	pid_t pid;
	int fd;

	umask(0);

	pid = fork();

	if (-1 == pid) {
		syslog(LOG_ERR, "Error forking process: %s\n", strerror(errno));
		return -1;
	}

	if (pid > 0) {
		// 父进程终止
		_exit(0);
	}

	if (-1 == setsid()) {
		syslog(LOG_ERR, "Error getting session id: %s\n", strerror(errno));
		return -1;
	}
	chdir("/");

	fd = open("/dev/null", O_RDWR);
	if (-1 == fd) {
		perror("Error opening file");
		return -1;
	}

	dup2(fd, 0);
	dup2(fd, 1);
	dup2(fd, 2);

	return 0;
}

// 借助文件锁判断守护进程是否已经在运行
int already_running(void) {
	int fd;
	char buf[BUFSIZE];

	fd = open(LOCKFILE, O_RDWR | O_CREAT, LOCKMODE);

	if (fd < 0) {
		syslog(LOG_ERR, "Error opening %s: %s\n", LOCKFILE, strerror(errno));
		exit(1);
	}

	if (-1 == flock(fd, LOCK_EX)) { // 加锁失败
		syslog(LOG_ERR, "Error locking file %s: %s\n", LOCKFILE, strerror(errno));
		exit(1);
	}
	ftruncate(fd, 0);
	sprintf(buf, "%ld", (long) getpid());
	write(fd, buf, strlen(buf) + 1);

	return 0;
}

